using HalconDotNet;  // 引入Halcon.NET库，用于图像处理和机器视觉
using System.Windows.Forms;  // Windows窗体基础命名空间
namespace 通用车牌识别联合编程
{
    public partial class Form1 : Form  // 主窗体类
    {
        //连接相机
        // 声明全局变量
        private HWindow _hWindow; //显示窗体的引用
        private HFramegrabber _framegrabber; //相机采集器
        private bool _isGrabbing = false; //是否继续采集
        private Thread _grabThread; //声明一个实时采集图像的线程

        // 在类中添加这些成员变量
        private List<string> imageFiles = new List<string>();  // 存储目录中的所有图片文件路径
        private int currentIndex = -1;  // 当前显示的图片索引
        private string currentDirectory = "";  // 当前图片所在目录

        // Halcon对象声明
        HObject ho_Image, ho_GrayImage, ho_Region;  // 图像对象、灰度图像对象、区域对象
        HObject ho_ConnectedRegions, ho_SelectedRegions, ho_RegionFillUp;  // 区域处理相关对象
        HObject ho_RegionTrans, ho_ImageReduced, ho_ImageAffineTrans1;  // 变换和裁剪图像对象
        HImage image;  // Halcon图像对象
        HRegion region;  // Halcon区域对象
        // 图像变换相关对象
        HObject ho_ImageAffineTrans, ho_RegionAffineTrans, ho_ImageReduced1;
        // Halcon元组变量声明（用于存储计算结果）
        HTuple hv_Area = new HTuple(), hv_Row = new HTuple();  // 区域面积和行坐标
        HTuple hv_Column = new HTuple(), hv_Phi = new HTuple();  // 列坐标和角度
        HTuple hv_HomMat2D = new HTuple();  // 二维齐次变换矩阵
        public Form1()
        {
            InitializeComponent();  // 初始化窗体组件
                                    // 创建状态标签

            // 为hswcCar控件添加鼠标滚轮事件处理
            hswcCar.MouseWheel += (sender, e) =>
            {
                // 调用自定义的鼠标滚轮处理方法（实现图像缩放功能）
                hswcCar.HSmartWindowControl_MouseWheel(sender, e);
            };
            hswcCarROI.MouseWheel += (sender, e) =>
            {
                // 调用自定义的鼠标滚轮处理方法（实现图像缩放功能）
                hswcCarROI.HSmartWindowControl_MouseWheel(sender, e);
            };
            InitializeCamera();
        }

        // 初始化相机
        private void InitializeCamera()
        {
            try
            {
                // 打开相机（参数需根据相机类型调整）
                _framegrabber = new HFramegrabber("GigEVision2", 0, 0, 0, 0, 0, 0, "default",
                                                  -1, "default", -1, "false", "default",
                                                  "default", 0, -1);

                // 获取 HSmartWindowControl 的 Halcon 窗口句柄
                _hWindow = hswcCar.HalconWindow;
            }
            catch (HalconException ex)
            {
                //MessageBox.Show($"相机初始化失败: {ex.Message}");
            }
        }
        // 开始实时采集
        private void StartGrabbing()
        {
            if (_framegrabber == null) InitializeCamera();

            _isGrabbing = true;
            //定义线程，在线程方法进行图像循环采集
            _grabThread = new Thread(GrabLoop);
            _grabThread.IsBackground = true;
            _grabThread.Start();
        }
        // 采集循环（在独立线程中运行）
        //private void GrabLoop()
        //{
        //    while (_isGrabbing)
        //    {
        //        try
        //        {
        //            // 抓取图像
        //            image = _framegrabber.GrabImageAsync(-1);

        //            // 在 Halcon 窗口中显示图像
        //            _hWindow.DispObj(image);
        //            hswcCar.SetFullImagePart();
        //            image.Dispose();
        //        }
        //        catch (HalconException ex)
        //        {
        //            // 处理异常（如相机断开）
        //            if (ex.GetErrorCode() == 5302) // 采集超时
        //                Thread.Sleep(1000);
        //            else
        //                break;
        //        }
        //    }
        //}
        // 停止采集
        private void StopGrabbing()
        {
            _isGrabbing = false;
            _grabThread?.Join(); // 等待线程结束
            _framegrabber?.Dispose();
            _framegrabber = null;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "所有图片|*.bmp;*.jpg;*.png;*.jpeg";
            openFileDialog.Title = "加载图片";
            openFileDialog.RestoreDirectory = true;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                // 获取所选文件所在目录
                currentDirectory = Path.GetDirectoryName(openFileDialog.FileName);

                // 获取目录中所有支持的图片文件
                imageFiles = Directory.GetFiles(currentDirectory, "*.*", SearchOption.TopDirectoryOnly)
                    .Where(file => file.ToLower().EndsWith(".bmp") ||
                                   file.ToLower().EndsWith(".jpg") ||
                                   file.ToLower().EndsWith(".jpeg") ||
                                   file.ToLower().EndsWith(".png"))
                    .OrderBy(f => f)
                    .ToList();

                // 设置当前索引
                currentIndex = imageFiles.IndexOf(openFileDialog.FileName);

                // 加载并显示图片
                LoadCurrentImage();
            }
            //StartGrabbing();
        }
        private void button2_Click(object sender, EventArgs e)
        {
            // 检测图像中文本行的方向角度（用于校正倾斜）
            // 参数说明：输入图像, 处理区域, 字符高度估计值, 角度下限(-50°), 角度上限(50°), 输出角度
            HOperatorSet.TextLineOrientation(image, image, 50, -50 * Math.PI / 180, 50 * Math.PI / 180, out HTuple angle);
            // 将检测到的角度转换为double类型（弧度制）
            double phi = angle;
            // 根据检测到的角度旋转图像（校正倾斜）
            // 参数说明：旋转角度(转换为度)，边缘填充模式
            HImage rotageImage = image.RotateImage(-phi / Math.PI * 180, "constant");
            // 增强图像对比度（突出细节）
            // 参数说明：掩模宽度, 掩模高度, 增强因子
            HImage ImageEmphasize = rotageImage.Emphasize(7, 7, 1);
            // 应用中值滤波（降噪）
            // 参数说明：滤波器类型, 滤波器尺寸, 边界处理模式
            HImage ImageMedian = rotageImage.MedianImage("circle", 5, "mirrored");
            // 将RGB图像分解为三个通道（红、绿、蓝）
            HImage redImage = ImageEmphasize.Decompose3(out HImage greenImage, out HImage blueImage);
            // 将RGB颜色空间转换为HSV颜色空间
            // 参数说明：输出H/S/V通道，转换模式
            HImage HImage = redImage.TransFromRgb(greenImage, blueImage, out HImage Simage, out HImage VImage, "hsv");
            //自动局部阈值分割
            HRegion region = Simage.BinaryThreshold("max_separability", "light", out HTuple usedThreshold);
            //开运算
            HRegion RegionOpening = region.OpeningCircle(2D);
            //区域连通
            HRegion ConnectedRegions = RegionOpening.Connection();
            //特征提取
            HRegion SelectedRegions = ConnectedRegions.SelectShape("area", "and", 32000D, 350000).SelectShape("rectangularity", "and", 0.4, 1).SelectShape("row", "and", 0, 2780);
            //膨胀
            HRegion RegionDilation1 = SelectedRegions.DilationCircle(8D);
            //填充
            HRegion RegionFillUp1 = RegionDilation1.FillUp();
            //合并
            HRegion RegionUnion1 = RegionFillUp1.Union1();
            //连通
            HRegion ConnectedRegions2 = RegionUnion1.Connection();
            //转换为对应有角度的矩形
            HRegion RegionTrans2 = ConnectedRegions2.ShapeTrans("rectangle2");
            //获取矩形的个数
            int Number = RegionTrans2.CountObj();
            //通过循环判断长轴和短轴之比
            HOperatorSet.GenEmptyObj(out HObject ROI);

            for (int i = 1; i <= Number; i++)
            {
                HRegion ObjectSelected = RegionTrans2.SelectObj(i);
                //获取区域的长轴
                double chang = ObjectSelected.RegionFeatures("rect2_len1");
                //获取区域的短轴
                double duan = ObjectSelected.RegionFeatures("rect2_len2");
                double value = chang / duan;
                if (value >= 2.8 && value <= 4.3)
                {
                    ROI = ROI.ConcatObj(ObjectSelected);
                }
            }
            //********************************New************************************
            //读取ROI的个数
            int Number1 = ROI.CountObj();
            if (Number1 == 1)
            {
                //腐蚀
                // 将HObject转换为HRegion后再进行腐蚀操作
                HRegion regionROI = new HRegion(ROI);
                HRegion RegionErosion1 = regionROI.ErosionRectangle1(80, 80);
                //裁剪
                HImage ImageReduced = ImageMedian.ReduceDomain(RegionErosion1);
                HRegion Region1 = ImageReduced.BinaryThreshold("max_separability", "light", out HTuple usedThreshold1);
                //连通
                HRegion ConnectedRegions1 = Region1.Connection();
                HRegion SelectedRegions1 = ConnectedRegions1.SelectShape("contlength", "and", 105, 150000).SelectShape("area", "and", 500, 100000);
                //膨胀
                HRegion RegionDilation = SelectedRegions1.DilationCircle(8D);
                //合并
                HRegion RegionUnion = RegionDilation.Union1();
                //连通
                HRegion ConnectedRegions3 = RegionUnion.Connection();
                //求交集
                HRegion RegionIntersection = ConnectedRegions3.Intersection(SelectedRegions1);
                //排序
                HRegion SortedRegions = RegionIntersection.SortRegion("character", "true", "row");

                //加载omc文件
                HOCRMlp mlp = new HOCRMlp();
                mlp.ReadOcrClassMlp("charact.omc");
                //进行OCR识别
                HTuple carNo = mlp.DoOcrMultiClassMlp(SortedRegions, ImageReduced, out HTuple con);
                textBox1.Text = string.Join("", carNo);


                //************************显示**************************
                // 清空Halcon窗口内容
                this.hswcCar.HalconWindow.ClearWindow();
                //设置颜色为绿色
                this.hswcCar.HalconWindow.SetColor("green");
                // 显示旋转校正后的图像
                this.hswcCar.HalconWindow.DispObj(ImageEmphasize);
                // 重置窗口显示为完整图像（自适应显示）
                this.hswcCar.SetFullImagePart();

                // 清空Halcon窗口内容
                this.hswcCarROI.HalconWindow.ClearWindow();
                //设置颜色为绿色
                this.hswcCarROI.HalconWindow.SetColor("green");
                // 显示旋转校正后的图像
                this.hswcCarROI.HalconWindow.DispObj(ImageReduced);         // 再显示ROI区域

                // 新增代码：自动适配显示ROI区域
                if (ImageReduced.CountObj() == 1)
                {
                    // 获取ROI区域的外接矩形坐标
                    HTuple row1, column1, row2, column2;
                    HOperatorSet.SmallestRectangle1(ImageReduced, out row1, out column1, out row2, out column2);

                    // 计算显示区域中心点和大小
                    double centerRow = (row1.D + row2.D) / 2.0;
                    double centerCol = (column1.D + column2.D) / 2.0;
                    double height = row2.D - row1.D;
                    double width = column2.D - column1.D;

                    // 设置窗口显示区域（扩大1.5倍区域以便更好查看）
                    double zoomFactor = 1.5;
                    HOperatorSet.SetPart(hswcCarROI.HalconWindow,
                                        centerRow - height * zoomFactor / 2.0,
                                        centerCol - width * zoomFactor / 2.0,
                                        centerRow + height * zoomFactor / 2.0,
                                        centerCol + width * zoomFactor / 2.0);
                }
            }
            else
            {
                HRegion regionROI1 = new HRegion(ROI);
                HRegion RegionErosion2 = regionROI1.SelectShape("area", "and", 110000, 340000);
                //矩形腐蚀操作(使用更大的核)
                HRegion RegionErosion = RegionErosion2.ErosionRectangle1(80, 120);
                //分割
                HImage ImageReduced1 = ImageMedian.ReduceDomain(RegionErosion);
                //对裁剪图像进行二值化
                HRegion Region2 = ImageReduced1.BinaryThreshold("max_separability", "light", out HTuple usedThreshold2);
                //连接区域(获取字符候选)
                HRegion ConnectedRegions4 = Region2.Connection();
                //根据形状特征筛选字符区域
                HRegion SelectedRegions2 = ConnectedRegions4.SelectShape("area", "and", 500, 100000).SelectShape("area", "and", 105, 150000);
                //圆形膨胀(扩大字符区域)
                HRegion RegionDilation2 = SelectedRegions2.DilationCircle(8D);
                //合并所有字符区域
                HRegion RegionUnion2 = RegionDilation2.Union1();
                //重新连接区域
                HRegion ConnectedRegions5 = RegionUnion2.Connection();
                //取膨胀后区域与原字符区域的交集
                HRegion RegionIntersection1 = ConnectedRegions5.Intersection(SelectedRegions2);
                //对字符区域排序(从左到右)
                HRegion SortedRegions1 = RegionIntersection1.SortRegion("character", "true", "row");
                //加载OCR分类器(字符识别模型)
                //加载omc文件
                HOCRMlp mlp1 = new HOCRMlp();
                mlp1.ReadOcrClassMlp("charact.omc");
                //进行OCR识别
                HTuple carNo1 = mlp1.DoOcrMultiClassMlp(SortedRegions1, ImageReduced1, out HTuple con1);
                textBox1.Text = string.Join("", carNo1);

                //************************显示**************************
                // 清空Halcon窗口内容
                this.hswcCar.HalconWindow.ClearWindow();
                //设置颜色为绿色
                this.hswcCar.HalconWindow.SetColor("green");
                // 显示旋转校正后的图像
                this.hswcCar.HalconWindow.DispObj(ImageEmphasize);
                // 重置窗口显示为完整图像（自适应显示）
                this.hswcCar.SetFullImagePart();

                // 清空Halcon窗口内容
                this.hswcCarROI.HalconWindow.ClearWindow();
                //设置颜色为绿色
                this.hswcCarROI.HalconWindow.SetColor("green");
                // 显示旋转校正后的图像
                this.hswcCarROI.HalconWindow.DispObj(ImageReduced1);         // 再显示ROI区域

                // 新增代码：自动适配显示ROI区域
                if (ImageReduced1.CountObj() == 1)
                {
                    // 获取ROI区域的外接矩形坐标
                    HTuple row1, column1, row2, column2;
                    HOperatorSet.SmallestRectangle1(ImageReduced1, out row1, out column1, out row2, out column2);

                    // 计算显示区域中心点和大小
                    double centerRow = (row1.D + row2.D) / 2.0;
                    double centerCol = (column1.D + column2.D) / 2.0;
                    double height = row2.D - row1.D;
                    double width = column2.D - column1.D;

                    // 设置窗口显示区域（扩大1.5倍区域以便更好查看）
                    double zoomFactor = 1.5;
                    HOperatorSet.SetPart(hswcCarROI.HalconWindow,
                                        centerRow - height * zoomFactor / 2.0,
                                        centerCol - width * zoomFactor / 2.0,
                                        centerRow + height * zoomFactor / 2.0,
                                        centerCol + width * zoomFactor / 2.0);
                }
            }
        }
        private void LoadCurrentImage()
        {
            if (currentIndex >= 0 && currentIndex < imageFiles.Count)
            {
                try
                {
                    // 加载图片
                    image = new HImage(imageFiles[currentIndex]);

                    // 在主窗口显示
                    hswcCar.HalconWindow.ClearWindow();
                    hswcCar.HalconWindow.DispObj(image);
                    hswcCar.SetFullImagePart();

                    // 清空ROI窗口和识别结果
                    hswcCarROI.HalconWindow.ClearWindow();
                    textBox1.Text = "";

                    // 更新状态显示
                    UpdateStatus();
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"加载图片失败: {ex.Message}");
                }
            }
        }

        // 新增方法：更新状态显示
        private void UpdateStatus()
        {
            if (imageFiles.Count > 0 && currentIndex >= 0)
            {
                lblStatus.Text = $"图片 {currentIndex + 1}/{imageFiles.Count}: {Path.GetFileName(imageFiles[currentIndex])}";
            }
            else
            {
                lblStatus.Text = "没有加载图片";
            }
        }

        // 上一张按钮
        private void button3_Click(object sender, EventArgs e)
        {
            if (imageFiles.Count == 0) return;

            currentIndex--;
            if (currentIndex < 0)
            {
                currentIndex = imageFiles.Count - 1;  // 循环到最后一张
            }

            LoadCurrentImage();
            //自动触发button2 点击事件
            button2?.PerformClick();
        }

        // 下一张按钮
        private void button4_Click(object sender, EventArgs e)
        {
            if (imageFiles.Count == 0) return;

            currentIndex++;
            if (currentIndex >= imageFiles.Count)
            {
                currentIndex = 0;  // 循环到第一张
            }

            LoadCurrentImage();
            //自动触发button2 点击事件
            button2?.PerformClick();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
        // 在类中添加成员变量
        private HImage _currentGrabbedImage = null; // 用于存储当前抓取的图像
        private readonly object _imageLock = new object(); // 用于线程安全的锁对象

        // 修改 GrabLoop 方法，保存当前抓取的图像
        private void GrabLoop()
        {
            while (_isGrabbing)
            {
                try
                {
                    // 抓取图像
                    HImage grabbedImage = _framegrabber.GrabImageAsync(-1);

                    // 在 Halcon 窗口中显示图像
                    _hWindow.DispObj(grabbedImage);
                    hswcCar.SetFullImagePart();

                    // 保存当前帧到成员变量（线程安全）
                    lock (_imageLock)
                    {
                        // 释放之前的图像
                        if (_currentGrabbedImage != null && _currentGrabbedImage.IsInitialized())
                        {
                            _currentGrabbedImage.Dispose();
                        }
                        _currentGrabbedImage = grabbedImage.CopyImage(); // 复制图像以保存
                    }

                    // 释放原始图像（复制后不需要保留）
                    grabbedImage.Dispose();
                }
                catch (HalconException ex)
                {
                    // 处理异常
                    if (ex.GetErrorCode() == 5302) // 采集超时
                        Thread.Sleep(1000);
                    else
                        break;
                }
            }
        }

        // 修改 button5_Click 方法，保存当前抓取的图像
        private void button5_Click(object sender, EventArgs e)
        {
            HImage imageToSave = null;

            // 安全获取当前图像
            lock (_imageLock)
            {
                if (_currentGrabbedImage != null && _currentGrabbedImage.IsInitialized())
                {
                    imageToSave = _currentGrabbedImage.CopyImage();
                }
            }

            if (imageToSave == null)
            {
                MessageBox.Show("没有可保存的图像！请先启动采集。", "警告",
                               MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            try
            {
                // 桌面文件夹路径
                string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                string saveFolder = Path.Combine(desktopPath, "车牌采集图像");

                // 创建文件夹（如果不存在）
                if (!Directory.Exists(saveFolder))
                {
                    Directory.CreateDirectory(saveFolder);
                }

                // 生成带时间戳的文件名
                string fileName = $"车牌图像_{DateTime.Now:yyyyMMdd_HHmmssfff}.png";
                string fullPath = Path.Combine(saveFolder, fileName);

                // 保存图像（PNG格式）
                imageToSave.WriteImage("png", 0, fullPath);

                // 提示保存成功
                MessageBox.Show($"图像保存成功！\n路径：{fullPath}", "保存成功",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"保存图像失败：{ex.Message}", "错误",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                // 释放复制的图像
                imageToSave?.Dispose();
            }
        }
    }
}